package com.kk.datastructure.linkedlist.improve;

/**
 * title: 单链表案例(增强版)
 * @author 阿K
 * 2020年11月22日 下午10:00:09 
 */
public class SingleLinkedListDemo {

	public static void main(String[] args) {
		//先创建节点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
		
		//创建要给链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero4);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		
		// singleLinkedList.addByOrder(hero3);		
		// singleLinkedList.list();
		
		// 修改
//		singleLinkedList.update(new HeroNode(1, "送浆", "白日"));
//		singleLinkedList.list();
		
		// 删除
		singleLinkedList.delete(1);
		singleLinkedList.delete(2);
		singleLinkedList.delete(3);
		singleLinkedList.delete(4);
		singleLinkedList.list();

	}

}

//定义HeroNode ， 每个HeroNode 对象就是一个节点
class HeroNode {
	public int no;		   // 好汉排行
	public String name;	   // 好汉姓名
	public String nickname;// 好汉外号
	public HeroNode next;  //指向下一个节点（好汉）
	//构造器
	public HeroNode(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//为了显示方法，我们重新toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
	
}

// 定义 SingleLinkedList 管理梁山英雄
class SingleLinkedList{
	// 先初始化一个头节点,头节点不能动,不存放具体的数据（可以理解为王伦 -- 初代寨主，后被林冲捅了）
	private HeroNode head = new HeroNode(0, null, null);
	
	// 返回头结点
	public HeroNode getHead() {
		return head;
	}
	
	// 删除	
	//1. head 不能动，因此我们需要一个temp辅助节点找到待删除节点的前一个节点
	//2. 说明我们在比较时，是temp.next.no 和  需要删除的节点的no比较
	public void delete(int no) {
		HeroNode temp = head;
		boolean flag = false;// 标志是否找到待删除节点
		while(true) {
			if(temp.next ==null)
				// 已经到链表的最后
				break;
			if(temp.next.no == no) {
				// 已经找到
				flag = true;
				break;
			}
			// 移动继续找
			temp = temp.next;
		}
		// 通过 flag 进行判断
		if(flag) {
			// 已经找到，指向后一个引用
			temp.next = temp.next.next;
		}else 
			System.out.printf("没有找到排行为【%d】要修改的英雄",no);		
	}
	
	// 更新节点的信息, 根据no编号来修改，即no编号不能改
	public void update(HeroNode heroNode) {
		// 判空
		if(head.next == null) {
			System.out.println("链表为空~~");
			return;
		}
		// 根据 no 找到需要修改的节点
		// 定义一个辅助变量
		HeroNode temp = head.next;
		boolean flag = false;// 表示是否找到节点
		while (true) {
			if (temp == null)
				// 链表已经遍历完
				break;
			if(temp.no == heroNode.no) {
				// 节点已经找到
				flag = true;
				break;
			}
			// 节点移动，继续找
			temp = temp.next;
		}
		
		// 根据 flag 判断
		if(flag) {
			// 找到，修改姓名和外号
			temp.name = heroNode.name;
			temp.nickname = heroNode.nickname;
		}else {
			System.out.printf("没有找到排行为【%d】要修改的英雄",heroNode.no);
		}
	}
		
	// 按编号顺序添加（如果有这个排名，则添加失败，并给出提示）
	public void addByOrder(HeroNode heroNode) {
		// 因为头节点不能动，因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
		// 因为单链表，因为我们找的temp 是位于 添加位置的前一个节点，否则插入不了
		HeroNode temp = head;
		boolean flag = false;// flag标志添加的编号是否存在，默认为false
		while(true) {
			if(temp.next == null) break;
			if(temp.next.no > heroNode.no)
				// 位置找到，就在 temp后面
				// 因为 它满足了 按顺序 ，所以可以插入
				break;
			if(temp.next.no == heroNode.no) {
				// 已经存在改排行的编号(不可重复)
				flag = true;
				break;
			}
			// 没满足以上，后移下一次节点继续找
			temp = temp.next;
		}
		
		// 对 flag 进行判断
		if(flag) 
			// 不能添加，说明编号已经存在
			System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);
		else {
			// 插入到链表中，temp的后面
			heroNode.next = temp.next;// 我后面的是6号，现在你后面是6号
			temp.next = heroNode;// 我后面是你
		}
	}
	
	
	// 遍历链表
	public void list() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空~~~");
			return;
		}
		// 因为头节点，不能动，因此我们需要一个辅助变量来遍历
		HeroNode temp = head.next;

		while (true) {
			// 判断是否到链表的最后
			if (temp == null)
				return;

			// 输出节点信息
			System.out.println(temp);
			// 将节点后移，注意要加！！
			temp = temp.next;
		}
	}
}
